#ifndef __FASTMATH_HPP__
#define __FASTMATH_HPP__

#include <cmath>

namespace utils {
class FastMath {
	
	public:static FastMath fastMath;
	
	public:static const double PI;
	
	private:double * sint;
	private:double * cost;
	private:double * tant;
	private:double bootTmp;
	
	private:FastMath(int boot = 1048576) {
		sint = new double[boot];
		cost = new double[boot];
		tant = new double[boot];

		bootTmp = (double)boot / (2.0 * PI);

		double tmp = 0.0, each = 2 * PI / boot;
		for(int i = 0; i < boot; ++i) {
			tmp = each * i;
			sint[i] = ::sin(tmp);
			cost[i] = ::cos(tmp);
			tant[i] = ::tan(tmp);
		}
	}
	
	public:~FastMath(void) {
		delete [] sint;
		delete [] cost;
		delete [] tant;
	}
	
	public:double sin(double i) const {
		//i %= 2.0 * PI;
		i -= ((int)(i / (2.0 * PI)) << 1) * PI;
		if(i < 0) return - sint[(int)(bootTmp * -i)];
		return sint[(int)(bootTmp * i)];
	}

	public:double cos(double i) const {
		i -= ((int)(i / (2.0 * PI)) << 1) * PI;
		return cost[(int)(bootTmp * abs(i))];
	}

	public:double tan(double i) const {
		i -= ((int)(i / (2.0 * PI)) << 1) * PI;
		if(i < 0) return - tant[(int)(bootTmp * -i)];
		return tant[(int)(bootTmp * i)];
	}

	public:int absI(int x) const {
		return x < 0? -x: x;
	}
	/*
	public:template<typename T> T mod(const T& a, const T& b) {
		return a - ((int)a / (int)b) * b;
	}
	*/
	public:template<typename T> T mod(T a, T b) {
		return a - ((int)a / (int)b) * b;
	}
};

const double FastMath::PI =  3.141592653589793;
FastMath FastMath::fastMath;
};
#endif
